package com.devbobcorn.nekoration.items;

import com.devbobcorn.nekoration.entities.PaintingEntity;
import com.devbobcorn.nekoration.utils.TagTypes;

import java.util.UUID;

import javax.annotation.Nullable;

import com.devbobcorn.nekoration.client.ClientHelper;

import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;

public class PaintingItem extends Item {
	public static final String TYPE = "type";
    public static final String WIDTH = "width";
    public static final String HEIGHT = "height";
	public static final String DATAID = "dataid";
	public static final String PIXELS = "pixels";
	public static final String ENTITYID = "entityid";

    public enum Type {
        BLANK((byte) 0, "blank"),
        PAINTED((byte) 1, "painted"),
        MAGIC((byte) 2, "magic");

        Type(byte id, String name){
			this.id = id;
            this.name = name;
        }

		public static Type fromId(byte id){
			for (Type p : Type.values()) {
				if (p.id == id)
					return p;
			}
			return Type.BLANK;
		}

		public final byte id;
        public final String name;
    }

	public PaintingItem(Properties settings) {
		super(settings);
	}

	public static float getTypePropertyOverride(ItemStack itemStack, @Nullable World world, @Nullable LivingEntity livingEntity){
		return (float) getType(itemStack);
	}

	public ActionResultType useOn(ItemUseContext ctx) {
		BlockPos blockpos = ctx.getClickedPos();
		Direction direction = ctx.getClickedFace();
		BlockPos blockpos1 = blockpos.relative(direction);
		PlayerEntity player = ctx.getPlayer();
		ItemStack stack = ctx.getItemInHand();
		if (player != null && !this.mayPlace(player, direction, stack, blockpos1)) {
			return ActionResultType.FAIL;
		} else {
			World world = ctx.getLevel();
			PaintingEntity painting;
			CompoundNBT tag = stack.getOrCreateTag();
			if (tag.contains(TYPE, TagTypes.BYTE_NBT_ID)) {
				if (tag.getByte(TYPE) == Type.PAINTED.id) {
					// Then make the painting with existing data...
					painting = new PaintingEntity(world, blockpos1, direction, (short)(PaintingItem.getWidth(stack) * 16), (short)(PaintingItem.getHeight(stack) * 16), tag.getUUID(DATAID));
					if (!world.isClientSide) painting.data.setPixels(tag.getIntArray(PIXELS)); // Meanless to operate on client-side as it'll not be actually added into the world...
				} else if (tag.getByte(TYPE) == Type.MAGIC.id) {
					painting = new PaintingEntity(world, blockpos1, direction, (short)(PaintingItem.getWidth(stack) * 16), (short)(PaintingItem.getHeight(stack) * 16), tag.getUUID(DATAID));
					Entity entity;
					if ((entity = world.getEntity(tag.getInt(ENTITYID))) instanceof PaintingEntity)
						painting.data.setPixels(((PaintingEntity)entity).data.getPixels().clone());
					else {
						if (world.isClientSide)
							player.displayClientMessage(new TranslationTextComponent("gui.nekoration.message.link_expired"), true);
						return ActionResultType.FAIL;
					}
				} else painting = new PaintingEntity(world, blockpos1, direction, (short)(PaintingItem.getWidth(stack) * 16), (short)(PaintingItem.getHeight(stack) * 16));
			} else painting = new PaintingEntity(world, blockpos1, direction, (short)(PaintingItem.getWidth(stack) * 16), (short)(PaintingItem.getHeight(stack) * 16));
			painting.setPos(blockpos1.getX(), blockpos1.getY(), blockpos1.getZ());
			if (painting.survives()) {
				if (!world.isClientSide) {
					painting.playPlacementSound();
					//hangingentity.recalculateBoundingBox();
					world.addFreshEntity(painting);
				}
				stack.shrink(1);
				return ActionResultType.sidedSuccess(world.isClientSide);
			} else {
				return ActionResultType.CONSUME;
			}
		}
	}

	@SuppressWarnings("deprecation")
	public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
		ItemStack stack = player.getItemInHand(hand);
		CompoundNBT tag = stack.getOrCreateTag();
		boolean hasType = tag.contains(TYPE, TagTypes.BYTE_NBT_ID);
		if (!hasType || (hasType && tag.getByte(TYPE) == Type.BLANK.id)) { // If a blank one...
			if (world.isClientSide) {
				DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
					ClientHelper.showPaintingSizeScreen(hand, stack.getCount());
				});
			}
		} else if (hasType && tag.getByte(TYPE) == Type.MAGIC.id) { // If a magic link...
			if (!world.isClientSide) {
				tag.remove("DataId");
				tag.remove("EntityId");
				tag.putByte(TYPE, Type.BLANK.id);
			}
		}
		return ActionResult.<ItemStack>success(stack);
	}

	protected boolean mayPlace(PlayerEntity player, Direction dir, ItemStack stack, BlockPos pos) {
		return !dir.getAxis().isVertical() && player.mayUseItemAt(pos, dir, stack);
	}

    public static int getWidth(ItemStack stack) {
		short w = stack.getOrCreateTag().getShort(WIDTH);
		return w <= 0 ? 1 : w;
	}

    public static void setWidth(ItemStack stack, short w) {
        CompoundNBT tag = stack.getOrCreateTag();
        tag.putShort(WIDTH, w);
	}

	public static int getHeight(ItemStack stack) {
		short h = stack.getOrCreateTag().getShort(HEIGHT);
		return h <= 0 ? 1 : h;
	}

    public static void setHeight(ItemStack stack, short h) {
        CompoundNBT tag = stack.getOrCreateTag();
        tag.putShort(HEIGHT, h);
	}

	public static byte getType(ItemStack stack) {
		CompoundNBT tag = stack.getOrCreateTag();
		if (tag.contains(TYPE, TagTypes.BYTE_NBT_ID))
			return tag.getByte(TYPE);
		return Type.BLANK.id;
	}

    public static void setContent(ItemStack stack, short w, short h, UUID seed, int[] pixels) {
        CompoundNBT tag = stack.getOrCreateTag();
		tag.putByte(TYPE, Type.PAINTED.id);
		tag.putShort(WIDTH, w);
        tag.putShort(HEIGHT, h);
		tag.putUUID(DATAID, seed);
		tag.putIntArray(PIXELS, pixels);
	}

    public static void setSize(ItemStack stack, short w, short h) {
        CompoundNBT tag = stack.getOrCreateTag();
		tag.putByte(TYPE, Type.BLANK.id);
		tag.putShort(WIDTH, w);
        tag.putShort(HEIGHT, h);
	}

	public static void setLink(ItemStack stack, short w, short h, UUID DataId, int EntityId) {
        CompoundNBT tag = stack.getOrCreateTag();
		tag.putByte(TYPE, Type.MAGIC.id);
		tag.putShort(WIDTH, w);
        tag.putShort(HEIGHT, h);
		tag.putUUID(DATAID, DataId);
		tag.putInt(ENTITYID, EntityId);
	}

	@Override
	public ITextComponent getName(ItemStack stack) {
		return new TranslationTextComponent(this.getDescriptionId(stack) + '.' + Type.fromId(getType(stack)).name, getWidth(stack), getHeight(stack));
	}
}
